#pragma once

#include <string>

#include <DirectXMath.h>
#include <DirectXCollision.h>
using namespace DirectX;

#include "clkUtility.h"
#include "clkVec2.h"
#include "clkVec3.h"

#define CLK_CAMERA_FOV  (CLK_PI/4.0f)
#define CLK_CAMERA_NEAR (1.0f)
#define CLK_CAMERA_FAR  (10000.0f)

enum CLK_CAMERA_MODE
{
	CLK_CAMERA_FIRSTPERSON,
	CLK_CAMERA_THIRDPERSON,
};

class clkCamera
{
private:
	friend class clkDirect3D11;

	//camera type
	int m_type;

	//projection properties
	float m_fov;
	float m_nearPlane;
	float m_farPlane;
	float m_aspectRatio;
	V2DF  m_dimension;

	//view properties
	XMFLOAT4 m_frustum[6];
	XMFLOAT3 m_eye;
	XMFLOAT3 m_look;
	XMFLOAT3 m_right;
	XMFLOAT3 m_up;

	//camera movement
	float m_pitch;
	float m_yaw;
	float m_roll;

	//camera attachments
	float m_attachDistance;
	V3DF* m_attachPosition;

	//camera matrix
	XMFLOAT4X4 m_viewMatrix;
	XMFLOAT4X4 m_perspectiveMatrix;
	XMFLOAT4X4 m_orthogonalMatrix;
public:
	clkCamera();
	~clkCamera();

	void init(int a_type, V2DF a_dimension);
	void init(
		int   a_type,
		float a_fov,
		float a_nearPlane,
		float a_farPlane,
		V2DF  a_dimension);
	void shut();

	void update();
	void updateOrthogonal();
	void updateFirstPerson();
	void updateThirdPerson();
	void updateFrustum();

	void screenToView(
		V2DF   a_point,
		V3DF*  a_origin,
		V3DF*  a_direction);
	bool tritest(
		XMFLOAT3* a_triangle,
		XMFLOAT3  a_origin,
		XMFLOAT3  a_direction,
		float*    a_distance);
	bool raytest(
		V3DF   a_origin,
		V3DF   a_direction,
		V3DF*  a_vertices,
		int*   a_indices,
		float* a_distance);

	void applyPosition(V3DF a_pos){m_eye.x+=a_pos.x;m_eye.y+=a_pos.y;m_eye.z+=a_pos.z;}
	void applyPitch(float a_pitch){m_pitch+=a_pitch;}
	void applyYaw(float a_yaw){m_yaw+=a_yaw;}
	void applyRoll(float a_roll){m_roll+=a_roll;}
	void applyPitchYawRoll(V3DF a_vec){m_pitch+=a_vec.x;m_yaw+=a_vec.y;m_roll+=a_vec.z;}

	void setPosition(V3DF a_eye){m_eye=XMFLOAT3(a_eye.x,a_eye.y,a_eye.z);}
	void setPitch(float a_pitch){m_pitch=a_pitch;}
	void setYaw(float a_yaw){m_yaw=a_yaw;}
	void setRoll(float a_roll){m_roll=a_roll;}
	void setPitchYawRoll(V3DF a_vec){m_pitch=a_vec.x;m_yaw=a_vec.y;m_roll=a_vec.z;}

	void attachDistance(float a_attachDistance){m_attachDistance=a_attachDistance;}
	void attachPosition(V3DF* a_attachPosition){m_attachPosition=a_attachPosition;}
	
	V3DF getPosition(){return V3DF(m_eye.x,m_eye.y,m_eye.z);}
	V3DF getLook(){return V3DF(m_look.x,m_look.y,m_look.z);}
	V3DF getRight(){return V3DF(m_right.x,m_right.y,m_right.z);}
	V3DF getUp(){return V3DF(m_up.x,m_up.y,m_up.z);}
	float getPitch(){return m_pitch;}
	float getYaw(){return m_yaw;}
	float getRoll(){return m_roll;}
	float getAttachDistance(){return m_attachDistance;}

	XMFLOAT4X4 getViewMatrix(){return m_viewMatrix;}
	XMFLOAT4X4 getPersMatrix(){return m_perspectiveMatrix;}
	XMFLOAT4X4 getOrthMatrix(){return m_orthogonalMatrix;}
};